// Copyright (c) 2010 Thomas Stuefe
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#pragma once

#pragma managed(push, off)
#include "sqlite3.h"
#pragma managed(pop)

#include "IStatement.h"
#include "DatabaseImpl.h"

using namespace System;

namespace zencat {
namespace sqlite {


	private ref class StatementImpl : public IStatement {
	public:

		virtual property IDatabase^ Database {
			IDatabase^ get() { return _db; }
		}

		virtual property String^ Sql {
			String^ get() { return _sql; }
		}
		
		virtual property int ParameterCount {
			int get() { return _parameterCount; }
		}

		virtual property int ColumnCount {
			int get() { return _columnCount; }
		}

		virtual String^ GetColumnName(int columnNumber);

		virtual property array<String^>^ ColumnNames {
			array<String^>^ get();
		}

		virtual DataType GetColumnType(int columnNumber);

		virtual property array<DataType>^ ColumnTypes {
			array<DataType>^ get();
		}

		virtual void Close();

		virtual property bool IsOpen {
			bool get() { return _hdl ? true : false; }
		}

		virtual property bool HasData {
			bool get() { return _hasData; }
		}

		virtual void Reset();

		virtual bool Step();

		virtual void BindStringToParameter(String^ value, int index);

		virtual void BindInt64ToParameter(Int64 value, int index);

		virtual void BindDoubleToParameter(Double value, int index);

		virtual void BindNullToParameter(int index);

		virtual void BindParameters(array<String^>^ values);

		virtual String^ ColumnValueString(int column);

		virtual Int64 ColumnValueInt64(int column);

		virtual Double ColumnValueDouble(int column);

		virtual bool ColumnValueIsNULL(int column);

		virtual array<String^>^ ColumnValues();

	internal:

		StatementImpl(DatabaseImpl^ db, ::sqlite3_stmt* gdl, String^ sql);

		~StatementImpl();

		!StatementImpl();

	private:
		
		DatabaseImpl^ _db;
		::sqlite3* _dbHdl;

		::sqlite3_stmt* _hdl;

		String^ _sql;

		int _parameterCount;
		int _columnCount;
		array<String^>^ _columnNames;
		
		// true if the statement is a select statement
		// (not used for any "hard" processing only used for tracing)
		bool _isSelectStatement;

		bool _hasData;

		// helper function, checks if the column number is valid, if not, an exception is thrown
		void checkColumnNumber(int n);

		// helper function, checks if the parameter number is valid, if not, an exception is throwm
		void checkParameterNumber(int n);

	};

} // end namespace sqlite

} // end namespace zencat